/*
 * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
 * Scott McNutt <smcnutt@psyent.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <config.h>
#include <asm-generic/memory_layout.h>

/*************************************************************************
 * RESTART
 ************************************************************************/

.section ".text_entry","ax"

_start:
	wrctl   status, r0      /* Disable interrupts */
	/* ICACHE INIT -- only the icache line at the reset address
	 * is invalidated at reset. So the init must stay within
	 * the cache line size (8 words). If GERMS is used, we'll
	 * just be invalidating the cache a second time. If cache
	 * is not implemented initi behaves as nop.
	 */
	ori     r4, r0, %lo(ICACHE_LINE_SIZE)
	movhi   r5, %hi(ICACHE_SIZE)
	ori     r5, r5, %lo(ICACHE_SIZE)
0:	initi   r5
	sub     r5, r5, r4
	bgt     r5, r0, 0b
	br      _except_end   /* Skip the tramp */

	/* EXCEPTION TRAMPOLINE -- the following gets copied
	 * to the exception address (below), but is otherwise at the
	 * default exception vector offset (0x0020).
	 */
_except_start:
	movhi   et, %hi(_exception)
	ori     et, et, %lo(_exception)
	jmp     et
_except_end:

	/* INTERRUPTS -- for now, all interrupts masked and globally
	 * disabled.
	 */
	wrctl   ienable, r0  /* All disabled */

	/* DCACHE INIT -- if dcache not implemented, initd behaves as
	 * nop.
	 */
	movhi   r4, %hi(DCACHE_LINE_SIZE)
	ori     r4, r4, %lo(DCACHE_LINE_SIZE)
	movhi   r5, %hi(DCACHE_SIZE)
	ori     r5, r5, %lo(DCACHE_SIZE)
	mov     r6, r0
1:	initd   0(r6)
	add     r6, r6, r4
	bltu    r6, r5, 1b

	/* RELOCATE CODE, DATA & COMMAND TABLE -- the following code
	 * assumes code, data and the command table are all
	 * contiguous. This lets us relocate everything as a single
	 * block. Make sure the linker script matches this ;-)
	 */
	nextpc  r4
_cur:	movhi   r5, %hi(_cur - _start)
	ori     r5, r5, %lo(_cur - _start)
	sub     r4, r4, r5                 /* r4 <- cur _start */
	mov     r8, r4
	movhi   r5, %hi(_start)
	ori     r5, r5, %lo(_start)        /* r5 <- linked _start */
	beq     r4, r5, 3f

	movhi   r6, %hi(_edata)
	ori     r6, r6, %lo(_edata)
2:	ldwio   r7, 0(r4)
	addi    r4, r4, 4
	stwio   r7, 0(r5)
	addi    r5, r5, 4
	bne     r5, r6, 2b
3:

	/* ZERO BSS/SBSS -- bss and sbss are assumed to be adjacent
	 * and between __bss_start and _end.
	 */
	 movhi  r5, %hi(__bss_start)
	 ori    r5, r5, %lo(__bss_start)
	 movhi  r6, %hi(_end)
	 ori    r6, r6, %lo(_end)
	 beq    r5, r6, 5f

4:	stwio   r0, 0(r5)
	 addi   r5, r5, 4
	 bne    r5, r6, 4b
5:

	/* JUMP TO RELOC ADDR */
	movhi   r4, %hi(_reloc)
	ori     r4, r4, %lo(_reloc)
	jmp     r4
_reloc:

	/* COPY EXCEPTION TRAMPOLINE -- copy the tramp to the
	 * exception address. Define CONFIG_ROM_STUBS to prevent
	 * the copy (e.g. exception in flash or in other
	 * softare/firmware component).
	 */
#if !defined(CONFIG_ROM_STUBS)
	movhi   r4, %hi(_except_start)
	ori     r4, r4, %lo(_except_start)
	movhi   r5, %hi(_except_end)
	ori     r5, r5, %lo(_except_end)
	movhi   r6, %hi(EXCEPTION_ADDR)
	ori     r6, r6, %lo(EXCEPTION_ADDR)
	beq     r4, r6, 7f                  /* Skip if at proper addr */

6:	ldwio   r7, 0(r4)
	stwio   r7, 0(r6)
	addi    r4, r4, 4
	addi    r6, r6, 4
	bne     r4, r5, 6b
7:
#endif

	/* STACK INIT -- zero top two words for call back chain.
	 */
	movhi   sp, %hi(STACK_BASE)
	ori     sp, sp, %lo(STACK_BASE)
	addi    sp, sp, -8
	stw     r0, 0(sp)
	stw     r0, 4(sp)
	mov     fp, sp

        /* Set the global pointer */
	movhi   r26, %hi(_gp)
	ori     r26, r26, %lo(_gp)

	/*
	 * Call board_init -- never returns
	 */
	movhi   r4, %hi(nios_start_barebox@h)
	ori     r4, r4, %lo(nios_start_barebox@h)
	callr   r4

	/* NEVER RETURNS -- but branch to the _start just
	 * in case ;-)
	 */
	br      _start

